<template>
  <view class="picker">
    <view v-if="!poppable" class="picker__input" @click="handleClick">
      <template v-if="label">
        {{ label }}
      </template>
      <view v-else class="picker__placeholder">
        {{ placeholder }}
      </view>
    </view>
    <m-popup
      :visible="innerVisible"
      position="bottom"
      height="670rpx"
      :close-on-click-overlay="closeOnClickOverlay"
      :close-icon-position="closeIconPosition"
      :close-color="closeColor"
      :close-icon="closeIcon"
      :close-icon-size="closeIconSize"
      @close="handleClose"
      @open="handleOpen"
    >
      <view class="picker__bar">
        <view class="picker__title"> {{ title }} </view>
        <view class="picker__ok" @click="handleConfirm">{{ okText }}</view>
      </view>

      <view class="picker__column">
        <picker-view
          :value="pickerValue"
          class="picker__view"
          indicator-style="height: 44px"
          @change="handlePickerChange"
        >
          <picker-view-column v-for="(columnList, columnListIndex) in columnGroup" :key="columnListIndex">
            <view
              v-for="(columnItem, columnItemIndex) in columnList"
              :key="columnItemIndex"
              class="picker__column-item"
              :style="[getColumnItemStyle(columnItemIndex, columnListIndex)]"
            >
              {{ columnItem.label }}
            </view>
          </picker-view-column>
        </picker-view>
      </view>
    </m-popup>
  </view>
</template>

<script lang="ts">
import { defineComponent, reactive, toRefs, PropType, computed, inject, watch } from '@vue/composition-api'

interface IColumn {
  label: string
  value: string | number
  values?: IColumn[]
  children?: IColumn[]
}

export default defineComponent({
  props: {
    visible: {
      type: Boolean,
      default: false,
    },
    closeOnClickOverlay: {
      type: Boolean,
      default: false,
    },
    closeIconPosition: {
      type: String,
      default: 'top-left',
    },
    closeColor: {
      type: String,
      default: '#666',
    },
    closeIcon: {
      type: String,
      default: 'close',
    },
    closeIconSize: {
      type: Number,
      default: 20,
    },
    title: {
      type: String,
      default: '',
    },
    okText: {
      type: String,
      default: '确定',
    },
    /**
     * [{ label: '111', value: 0 }]
     *
     * [{ values: [{label: '111', value: 0}] }]
     *
     * [{ label: '111', value: 0, children: [] }]
     */
    options: {
      type: Array as PropType<IColumn[]>,
      default: () => [],
    },
    value: {
      type: [String, Number, Array],
      default: 0,
    },
    poppable: {
      type: Boolean,
      default: false,
    },
    placeholder: {
      type: String,
      default: '',
    },
  },
  emits: ['input', 'confirm', 'update:visible', 'close', 'open'],
  setup(props, { emit }) {
    const formItem: any = inject('formItem', null)
    const handleClose = () => {
      state.innerVisible = false
      emit('update:visible', false)
      emit('close')
    }
    const handleConfirm = () => {
      let index = state.pickerValue
      let item = state.columnGroup.map((columnList, columnListIndex) => {
        const columnIndex = index[columnListIndex]
        const column = columnList[columnIndex]

        return column
      })
      let val: any = item.map((x) => x.value)
      let label: any = item.map((x) => x.label)

      if (getType.value === 'text') {
        val = val[0]
        label = label[0]
      }

      emit('input', val)
      emit('confirm', label, val)
      state.label = label
      if (formItem && formItem.validate) {
        formItem && formItem.validate()
      }
      handleClose()
    }
    const getType = computed(() => {
      const firstColumn = props.options[0]

      if (typeof firstColumn === 'object') {
        if (firstColumn.children) {
          return 'cascade'
        } else if (firstColumn?.values) {
          return 'multipleColumns'
        }
      }

      return 'text'
    })

    const columnGroup = getType.value === 'text' ? [props.options] : props.options.map((x) => x.values as IColumn[])
    const getLabel = () => {
      if (getType.value === 'text') {
        const item = props.options.find((x) => x.value === props.value)

        return item && item.label
      }

      // TODO: 待完善
    }
    const state = reactive({
      innerVisible: props.visible,
      label: getLabel(),
      pickerValue: [0],
      columnGroup,
    })
    const handlePickerChange = (e) => {
      const newPickerValue = e.detail.value
      let oldIndex
      let newIndex
      let oldVal
      let newVal
      let columnIndex
      let values: string[] = []

      for (let i = 0; i < newPickerValue.length; i++) {
        newIndex = newPickerValue[i]
        newVal = state.columnGroup[i][newIndex].value
        values.push(newVal)
        if (state.pickerValue[i] !== newPickerValue[i]) {
          oldIndex = state.pickerValue[i]
          oldVal = state.columnGroup[i][oldIndex] && state.columnGroup[i][oldIndex].value

          columnIndex = i
          break
        }
      }

      state.pickerValue = e.detail.value
      emit('change', {
        oldIndex,
        newIndex,
        columnIndex,
        newVal,
        oldVal,
        values,
      })
    }
    const getColumnItemStyle = (columnItemIndex, columnListIndex) => {
      const val = state.pickerValue[columnListIndex]
      const map = {
        1: 36,
        0: 44,
      }
      const diff = Math.abs(val - columnItemIndex)
      const fontSize = map[diff] ? map[diff] : 32

      return {
        height: '44px',
        lineHeight: '44px',
        fontSize: fontSize + 'rpx',
      }
    }
    const setColumnValues = (index, columns, val) => {
      state.pickerValue[index] = columns.findIndex((x) => x.value === val)
      state.columnGroup[index] = columns
    }
    const handleClick = () => {
      state.innerVisible = true
    }

    const handleOpen = () => {
      state.pickerValue =
        getType.value === 'text'
          ? [props.options.findIndex((x) => x.value === props.value)]
          : props.options.map((group, groupIndex) => {
              const index = (group.values as IColumn[]).findIndex((x) => x.value === props.value[groupIndex])
              return Math.max(0, index)
            })

      emit('open')
    }

    watch(
      () => props.visible,
      (newVal) => (state.innerVisible = newVal)
    )

    watch(
      () => props.options,
      (newVal) => {
        state.columnGroup = getType.value === 'text' ? [newVal] : newVal.map((x) => x.values as IColumn[])
        state.pickerValue =
          getType.value === 'text'
            ? [newVal.findIndex((x) => x.value === props.value)]
            : newVal.map((group, groupIndex) => {
                return (group.values as IColumn[]).findIndex((x) => x.value === props.value[groupIndex])
              })
      }
    )

    return {
      ...toRefs(state),
      handleClick,
      handleClose,
      handleConfirm,
      handlePickerChange,
      getColumnItemStyle,
      setColumnValues,
      handleOpen,
    }
  },
})
</script>
<style lang="scss" scoped>
.picker {
  &__input {
    font-size: 28rpx;
  }
  &__placeholder {
    color: $--font-placeholder-c;
  }
  &__bar {
    position: relative;
    padding-top: 10rpx;
  }
  &__title {
    @include fz32;
    text-align: center;
  }
  &__ok {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    right: 8rpx;
    @include fz32;
    color: $--primary-c;
  }

  &__view {
    height: 500rpx;
    margin-top: 10rpx;
    font-size: 44rpx;
  }
  &__column-item {
    text-align: center;
    height: 88rpx;
    line-height: 88rpx;
    transition: font-size 0.3s ease;
  }
}
</style>
